/*
 * This file is part of the Refran Library
 * Copyright (C) 2009 César Enrique García
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/** @file
 * $Author: cquike@gmail.com $
 * $Date: 2011-11-22 11:00:43 +0000 (Tue, 22 Nov 2011) $
 * $Revision: 240 $
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <utility>

#include "Error.h"
#include "Recipe.h"


Refran::Recipe::Recipe() :
  Logger("refran.recipe"),
  m_state(Refran::RecipeState::INITIALIZING)
{
}

Refran::Recipe::Recipe(int                version,
                       const std::string& name,
                       const std::string& synopsis,
                       const std::string& longDesc,
                       const std::string& author,
                       const std::string& email,
                       const std::string& copyright,
                       const std::string& url,
                       const std::string& releaseComment) :
  Logger("refran.recipe."+name),
  m_state(Refran::RecipeState::INITIALIZING)
{
    init_(version, name, synopsis, longDesc, author, 
          email, copyright, url, releaseComment);
}

Refran::Recipe::~Recipe()
{
}

Refran::RecipeState Refran::Recipe::getState() const
{
    std::lock_guard<std::mutex> guard(m_state_mutex);
    return m_state;
}

void Refran::Recipe::go()
{
    debug_("Launching recipe %s",m_name.c_str());
    //Prepare to run
    prepareGo_();

    //Run the recipe implementation
    this->go_impl_();

    //Finish the run
    finishGo_();
    debug_("Finishing recipe %s",m_name.c_str());
}

const Refran::FrameSet& Refran::Recipe::getInputFrames() const
{
    return *m_InputFrames;
}

void Refran::Recipe::setInputFrames
(std::shared_ptr<Refran::FrameSet>& inputFrameSet)
{
    m_InputFrames = inputFrameSet;
    setState_(Refran::RecipeState::READY);
}

double Refran::Recipe::getProgress() const
{
    return m_fractionDone;
}

const std::string& Refran::Recipe::getAuthor() const
{
    return m_author;
}

const std::string& Refran::Recipe::getCopyright() const
{
    return m_copyright;
}

const std::string& Refran::Recipe::getDescription() const
{
    return m_longDesc;
}

const std::string& Refran::Recipe::getEmail() const
{
    return m_email;
}

const std::string& Refran::Recipe::getName() const
{
    return m_name;
}

int Refran::Recipe::getVersion() const
{
    return m_version;
}

const std::string& Refran::Recipe::getSynopsis() const
{
    return m_synopsis;
}

const std::string& Refran::Recipe::getURL() const
{
    return m_url;
}

const std::string& Refran::Recipe::getReleaseComment() const
{
    return m_releaseComment;
}

void Refran::Recipe::init_(int                version,
                           const std::string& name,
                           const std::string& synopsis,
                           const std::string& longDesc,
                           const std::string& author,
                           const std::string& email,
                           const std::string& copyright,
                           const std::string& url,
                           const std::string& releaseComment)
{
    m_version        = version;
    m_name           = name;
    m_synopsis       = synopsis;
    m_longDesc       = longDesc;
    m_author         = author;
    m_email          = email;
    m_copyright      = copyright;
    m_url            = url;
    m_releaseComment = releaseComment;
}

void Refran::Recipe::prepareGo_()
{
    //Check that we are in state READY
    if(m_state != Refran::RecipeState::READY)
    {
        throw Error(__func__, "Recipe is not in Ready state");
    }

    //Check that the inputs are compatible with what we expect
    //checkInputCompatibility_();

    //Check that the input frames exist
    //checkInputsExist();

    //The fraction done is equal 0
    m_fractionDone = 0;

    //Set the state to running
    setState_(Refran::RecipeState::RUNNING);
}

void Refran::Recipe::finishGo_()
{
    //The fraction done is equal 1
    m_fractionDone = 1;

    //Set the state to finish
    setState_(Refran::RecipeState::FINISHED);
}

void Refran::Recipe::setState_(const RecipeState& state)
{
    std::lock_guard<std::mutex> guard(m_state_mutex);
    m_state = state;
}

void Refran::Recipe::setProgress_(double fractionDone)
{
    if(fractionDone < m_fractionDone)
        return;
    if(fractionDone > 1)
        m_fractionDone = 1;
    if(fractionDone < 0)
        m_fractionDone = 0;
    m_fractionDone = fractionDone;
}
